import { MODEL_NAME } from '../../constants/model-names';
import type { ItemRarity } from '../../data/item/type';
import { EVENTS, type IEventBus } from '../../events';
import type {
  BattleModel,
  CultivationSkillModel,
  PlayerAttributesModel,
  PlayerProgressModel,
  SceneModel,
  UserInfoModel,
} from '../../model';
import { BattleUnit } from '../../model/battle/unit';
import { RewardDropCalculator, RewardUtils } from '../../model/reward';
import { REWARD_SOURCE_TYPE, type Reward } from '../../model/reward/type';
import { BaseSystem } from '../base';
import type { PlayerStateSystem } from '../player-state';

export class BattleSystem extends BaseSystem {
  private bus: IEventBus;
  private playerStateSystem: PlayerStateSystem;
  /** 战斗间隔时间(秒) */
  private battleInterval = 1;
  private battleIntervalTime = 0;

  constructor(bus: IEventBus, playerStateSystem: PlayerStateSystem) {
    super();
    this.bus = bus;
    this.playerStateSystem = playerStateSystem;

    this.bus.on(EVENTS.SCENE_EXPLORE_COMPLETED, () => {
      this.exploredStartBattle();
    });

    this.bus.on(EVENTS.BATTLE_END, (win) => {
      this.onBattleEnd(win);
    });

    this.bus.on(EVENTS.BATTLE_STOP, () => {
      const battleModel = this.playerStateSystem.getModel<BattleModel>(
        MODEL_NAME.BATTLE
      );
      battleModel.stopBattle();
    });

    this.bus.on(EVENTS.BATTLE_SET_AUTO_SELL_RARITY, (rarity) => {
      this.battleSetAutoSellRarity(rarity);
    });
  }

  /** 战斗结束相关 */
  private onBattleEnd(win: boolean) {
    const battleModel = this.playerStateSystem.getModel<BattleModel>(
      MODEL_NAME.BATTLE
    );
    if (!battleModel) return;
    const enemyUnits = battleModel.getEnemyUnits();
    this.recordKilledEnemies(enemyUnits);
    this.updateCultivationKillEnemies(enemyUnits);
    win ? this.battleWin() : this.battleLose();
  }

  /** 记录击杀的敌人 */
  private recordKilledEnemies(enemies: BattleUnit[]) {
    const playerProgressModel =
      this.playerStateSystem.getModel<PlayerProgressModel>(
        MODEL_NAME.PLAYER_PROGRESS
      );
    const enemyUnitsIds = enemies.map((unit) => unit.rawId);
    playerProgressModel.updateKillEnemiesByIds(enemyUnitsIds);
  }

  /** 已学功法击杀数更新 */
  private updateCultivationKillEnemies(enemies: BattleUnit[]) {
    const cultivationSkillModel =
      this.playerStateSystem.getModel<CultivationSkillModel>(
        MODEL_NAME.CULTIVATION_SKILL
      );
    const enemyUnitsIds = enemies.map((unit) => unit.rawId);
    cultivationSkillModel.updateCultivationKillEnemies(enemyUnitsIds);
  }

  private battleLose() {
    const sceneModel = this.playerStateSystem.getModel<SceneModel>(
      MODEL_NAME.SCENE
    );
    sceneModel.startExplore();
  }

  private battleWin() {
    const sceneModel = this.playerStateSystem.getModel<SceneModel>(
      MODEL_NAME.SCENE
    );
    if (!sceneModel) return;
    const enemies = sceneModel.getEnemies();
    const rewards: Reward[] = [];
    enemies.forEach((enemy) => {
      rewards.push(
        ...RewardDropCalculator.calculateMultiplePools(enemy.getRewards())
      );
    });
    const mergeRewards = RewardUtils.mergeRewardsSafe(rewards);
    this.bus.emit(EVENTS.REWARD_ISSUE, mergeRewards, REWARD_SOURCE_TYPE.BATTLE);
  }

  /** 探索完成后自动开始战斗 */
  private exploredStartBattle() {
    const battleModel = this.playerStateSystem.getModel<BattleModel>(
      MODEL_NAME.BATTLE
    );
    const playerAttributesModel =
      this.playerStateSystem.getModel<PlayerAttributesModel>(
        MODEL_NAME.PLAYER_ATTRIBUTES
      );
    const sceneModel = this.playerStateSystem.getModel<SceneModel>(
      MODEL_NAME.SCENE
    );
    const userInfoModel = this.playerStateSystem.getModel<UserInfoModel>(
      MODEL_NAME.USER_INFO
    );
    if (!battleModel || !playerAttributesModel || !sceneModel || !userInfoModel)
      return;
    battleModel.reset();
    const username = userInfoModel.getUsername();
    const playerBattleUnit = BattleUnit.createPlayer(
      playerAttributesModel.calculateFinalAttributes()
    );
    playerBattleUnit.setName(username === '' ? '玩家' : username);
    battleModel.addUnit(playerBattleUnit);
    const enemies = sceneModel.getEnemies();
    enemies.forEach((enemy) => {
      battleModel.addUnit(BattleUnit.createEnemy(enemy));
    });
    battleModel.startBattle();
  }

  private battleSetAutoSellRarity(rarity: ItemRarity[]) {
    const battleModel = this.playerStateSystem.getModel<BattleModel>(
      MODEL_NAME.BATTLE
    );
    if (!battleModel) return;
    battleModel.setSettingsRarity(rarity);
  }

  public update(dt: number): void {
    const battleModel = this.playerStateSystem.getModel<BattleModel>(
      MODEL_NAME.BATTLE
    );
    if (!battleModel.getIsBattling()) return;
    this.battleIntervalTime += dt;
    if (this.battleIntervalTime >= this.battleInterval) {
      battleModel.executeSingleAction();
      this.battleIntervalTime = 0;
    }
  }
}
